home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / castools.zip / FAXUTILS.C < prev    next >
Text File  |  1990-01-18  |  20KB  |  724 lines

  1.  
  2.  
  3. /*
  4.    FAXUTILS.C  Utilities used by the FAX Toolkit Library.
  5. */
  6.  
  7. /*
  8.    SubmitSingleOk(ECS *task);
  9.  
  10.    This function examines an Event Control Structure to determine if it is
  11.    'OK' to use the low-level CASSubmitSingleFileToSend function.  It is "OK"
  12.    to use that function if all of the fields that it ignores are set to
  13.    NULL values.  If any of those fields are set to non-NULL values, using
  14.    SubmitSingle would lose that information, and would be not "OK".
  15.  
  16.    INPUT:  The Event Control Structure for the task under consideration.
  17.  
  18.    OUTPUT: 1 or 0.
  19. */
  20.  
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <ctype.h>
  24. #include <sys\types.h>
  25. #include <sys\stat.h>
  26. #include <malloc.h>
  27. #include <cas.h>
  28. #include <FAX.h>
  29.  
  30. int pascal SubmitSingleOk(ECS *task)
  31. {
  32.  
  33.   WORD FileCount;
  34.   FTRLIST *CurrFTRL;
  35.  
  36.   if (task->EventControlFile.SenderName[0] ||
  37.       task->EventControlFile.LogoFilePath[0]) {
  38.     return(0);
  39.   }
  40.   if (task->EventControlFile.TransferType != FILE_TRANSFER) {
  41.     if (task->FirstFTR->OneFTR.PageLength) {
  42.       return(0);
  43.     }
  44.   }
  45.   return(1);
  46. }
  47.  
  48. /*
  49.    ECSOkToSubmit(ECS *ecs);
  50.  
  51.    This function checks an Event Control Structure for errors.  It follows the
  52.    specifications for Control Files documented in CAS 1.0.  It returns 1 if the
  53.    ECS is valid for a task event.
  54.  
  55.    Reserved fields are tested for being zero; if not, they are zeroed and a
  56.    warning is set.  Likewise other fields used by the Resident Manager that
  57.    should be set to zero by the application are tested.  It they are not zero,
  58.    they are set to zero, and a warning is set.
  59.  
  60.    INPUT:  The Event Control Structure for the task under consideration.
  61.  
  62.    OUTPUT: 1 or 0.
  63. */
  64.  
  65. typedef struct {
  66.   unsigned day: 5;
  67.   unsigned month: 4;
  68.   unsigned year: 7;
  69. } DOS_fdate;
  70.  
  71. typedef struct {
  72.   unsigned twosecs: 5;
  73.   unsigned minute: 6;
  74.   unsigned hour: 5;
  75. } DOS_ftime;
  76.  
  77. static int days_in_month[2][13] = {
  78.   {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  79.   {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
  80. };
  81.  
  82. int pascal ECSOkToSubmit(ECS *ecs)
  83. {
  84.  
  85.   DOS_fdate *date;
  86.   DOS_ftime *time;
  87.   int i, leap, year;
  88.   unsigned month, day,
  89.            hour, minute, twosec;
  90.   FTRLIST *CurrFTRL;
  91.   struct stat fstatbuf;
  92.  
  93.   /* EventType check */
  94.   if ((ecs->EventControlFile.EventType != SEND) &&
  95.       (ecs->EventControlFile.EventType != POLLED_SEND) &&
  96.       (ecs->EventControlFile.EventType != POLLED_RECEIVE)) {
  97.     FAXerrno = BADEVENTTYPE;
  98.     return(0);
  99.   }
  100.  
  101.   /* TransferType check */
  102.   if ((ecs->EventControlFile.TransferType < FAX_200) ||
  103.       (ecs->EventControlFile.TransferType > FILE_TRANSFER)) {
  104.     FAXerrno = BADTRANSFERTYPE;
  105.     return(0);
  106.   }
  107.  
  108.   /* EventStatus check (non-reserved Resident Manager field) */
  109.   if (ecs->EventControlFile.EventStatus) {
  110.     ecs->EventControlFile.EventStatus = 0;
  111.     FAXerrno = FIELDZEROED;
  112.   }
  113.  
  114.   /* EventTime  check */
  115.   time = (DOS_ftime *)&ecs->EventControlFile.EventTime;
  116.   twosec = time->twosecs;
  117.   minute = time->minute;
  118.   hour = time->hour;
  119.   if ((twosec < 0) || (twosec > 29) ||
  120.       (minute < 0) || (minute > 59) ||
  121.       (hour < 0) || (hour > 23)) {
  122.     FAXerrno = BADEVENTTIME;
  123.     return(0);
  124.   }
  125.  
  126.   /* EventDate check, only if date is not NULL (NULL is OK) */
  127.   if (ecs->EventControlFile.EventDate) {
  128.     date = (DOS_fdate *)&ecs->EventControlFile.EventDate;
  129.     year = date->year;
  130.     month = date->month;
  131.     day = date->day;
  132.     if ((month < 1) || (month > 12) ||
  133.         (year < 0) || (year > 119)) {
  134.       FAXerrno = BADEVENTDATE;
  135.       return(0);
  136.     }
  137.     year = year + 1980;
  138.     leap = (year % 4 == 0) &&
  139.            (year % 100 != 0) ||
  140.            (year % 400 == 0);
  141.     if ((day < 1) || (day > days_in_month[leap][month])) {
  142.       FAXerrno = BADEVENTDATE;
  143.       return(0);
  144.     }
  145.   }
  146.  
  147.   /* FileCount  check */
  148.   if ((ecs->EventControlFile.FileCount < 0) ||
  149.       (ecs->EventControlFile.FileCount > 32766)) {
  150.     FAXerrno = FILECOUNTOUTOFRANGE;
  151.     return(0);
  152.   }
  153.  
  154.   /* FTROffset  check ?? how to check?*/
  155.  
  156.   /* Phone[]  check, only if NOT a POLLED_SEND, first for length...  */
  157.   if (ecs->EventControlFile.EventType != POLLED_SEND) {
  158.     for (i=0; i<PHONENUMLENGTH; i++) {
  159.       if (!ecs->EventControlFile.Phone[i]) {
  160.         break;
  161.       }
  162.     }
  163.     if (i == PHONENUMLENGTH) {
  164.       FAXerrno = STRINGTOOLONG;
  165.       ecs->EventControlFile.Phone[i - 1] = '\0';
  166.     }
  167.     if (i == 0) {
  168.       FAXerrno = BADPHONENUMBER;
  169.       return(0);
  170.     }
  171.  
  172.     /* ...then for validity */
  173.     /* (if first character is 'm' or 'M', rest is ok) */
  174.     if (tolower(ecs->EventControlFile.Phone[0]) != 'm') {
  175.       for (i=0; ecs->EventControlFile.Phone[i] && (i < PHONENUMLENGTH); i++) {
  176.         if ((ecs->EventControlFile.Phone[i] >= '0') &&
  177.             (ecs->EventControlFile.Phone[i] <= '9')) {
  178.           break;
  179.         }
  180.       }
  181.       if (!ecs->EventControlFile.Phone[i]) {
  182.         FAXerrno = BADPHONENUMBER;
  183.         return(0);
  184.       }
  185.     }
  186.   }
  187.  
  188.   /* ApplicationTag[]  check */
  189.   for (i=0; i<APPTAGLENGTH; i++) {
  190.     if (!ecs->EventControlFile.ApplicationTag[i]) {
  191.       break;
  192.     }
  193.     if (!(isascii(ecs->EventControlFile.ApplicationTag[i]))) {
  194.       FAXerrno = NONASCIISTRING;
  195.       return(0);
  196.     }
  197.   }
  198.   if (i == APPTAGLENGTH) {
  199.     FAXerrno = STRINGTOOLONG;
  200.     ecs->EventControlFile.ApplicationTag[i - 1] = '\0';
  201.   }
  202.  
  203.   /* RESERVED1  check */
  204.   if (ecs->EventControlFile.RESERVED1) {
  205.     FAXerrno = RESERVEDFIELDZEROED;
  206.     ecs->EventControlFile.RESERVED1 = 0;
  207.   }
  208.  
  209.   /* Some Resident manager (non-reserved) fields */
  210.   for (i=0; i<13; i++) {
  211.     if ((&ecs->EventControlFile.ConnectSeconds)[i]) {
  212.       FAXerrno = FIELDZEROED;
  213.       (&ecs->EventControlFile.ConnectSeconds)[i] = 0;
  214.     }
  215.   }
  216.  
  217.   /* SendCover  check */
  218.   if ((ecs->EventControlFile.SendCover != 0) &&
  219.       (ecs->EventControlFile.SendCover != 1)) {
  220.     FAXerrno = BADSENDCOVER;
  221.     return(0);
  222.   }
  223.  
  224.   /* Transmission errors (non-reserved) */
  225.   if (ecs->EventControlFile.ErrorCount) {
  226.     FAXerrno = FIELDZEROED;
  227.     ecs->EventControlFile.ErrorCount = 0;
  228.   }
  229.  
  230.   /* RESERVED2[]  check */
  231.   for (i=0; i<RESERVED2LENGTH; i++) {
  232.     if (ecs->EventControlFile.RESERVED2[i]) {
  233.       ecs->EventControlFile.RESERVED2[i] = 0;
  234.       FAXerrno = RESERVEDFIELDZEROED;
  235.     }
  236.   }
  237.  
  238.   /* RemoteCSID[]  check */
  239.   for (i=0; i<CSIDLENGTH; i++) {
  240.     if (ecs->EventControlFile.RemoteCSID[i]) {
  241.       FAXerrno = FIELDZEROED;
  242.       ecs->EventControlFile.RemoteCSID[i] = 0;
  243.     }
  244.   }
  245.  
  246.   /* DestinationName[]  check */
  247.   for (i=0; i<NAMELENGTH; i++) {
  248.     if (!ecs->EventControlFile.DestinationName[i]) {
  249.       break;
  250.     }
  251.     if (!(isascii(ecs->EventControlFile.DestinationName[i]))) {
  252.       FAXerrno = NONASCIISTRING;
  253.       return(0);
  254.     }
  255.   }
  256.   if (i == NAMELENGTH) {
  257.     FAXerrno = STRINGTOOLONG;
  258.     ecs->EventControlFile.DestinationName[i - 1] = '\0';
  259.   }
  260.  
  261.   /* SenderName[]  check first that it's a valid string ... */
  262.   for (i=0; i<NAMELENGTH; i++) {
  263.     if (!ecs->EventControlFile.SenderName[i]) {
  264.       break;
  265.     }
  266.     if (!(isascii(ecs->EventControlFile.SenderName[i]))) {
  267.       FAXerrno = NONASCIISTRING;
  268.       return(0);
  269.     }
  270.   }
  271.  
  272.   /* ...then that it's not too long (none is ok, the Toolkit will set it) */
  273.   if (i) {
  274.     if (i == NAMELENGTH) {
  275.       FAXerrno = STRINGTOOLONG;
  276.       ecs->EventControlFile.SenderName[i - 1] = '\0';
  277.     }
  278.   }
  279.  
  280.   /* LogoFilePath[]  check: first that it's valid, ..... */
  281.   for (i=0; i<FULLFNAMELENGTH; i++) {
  282.     if (!ecs->EventControlFile.LogoFilePath[i]) {
  283.       break;
  284.     }
  285.     if (!(isascii(ecs->EventControlFile.LogoFilePath[i]))) {
  286.       FAXerrno = NONASCIISTRING;
  287.       return(0);
  288.     }
  289.   }
  290.   if (i == FULLFNAMELENGTH) {
  291.     FAXerrno = STRINGTOOLONG;
  292.     ecs->EventControlFile.LogoFilePath[i - 1] = '\0';
  293.   }
  294.  
  295.   /* ... then, if named at all (Toolkit will set if not), that it's there */
  296.   if (i) {
  297.     if (stat(ecs->EventControlFile.LogoFilePath, &fstatbuf)) {
  298.       FAXerrno = LOGOFILENOTFOUND;
  299.       return(0);
  300.     }
  301.   }
  302.  
  303.   /* Checks of the coverpage text */
  304.   for (i=0; i<ecs->EventControlFile.FTROffset - 383; i++) {
  305.     if (!(isascii(ecs->CoverPageText[i]))) {
  306.       FAXerrno = NONASCIISTRING;
  307.       return(0);
  308.     }
  309.   }
  310.  
  311.   /* Check each of the FTR's, if any */
  312.   CurrFTRL = ecs->FirstFTR;
  313.   for (i=0; i<ecs->EventControlFile.FileCount; i++) {
  314.     if (!CurrFTRL) {
  315.       FAXerrno = BADFILECOUNT;
  316.       return(0);
  317.     }
  318.     else if (!(FTRLOkToSend(ecs, CurrFTRL))) {
  319.       return(0);                        /* FTRLOk sets FAXerrno */
  320.     }
  321.     CurrFTRL = CurrFTRL->next;
  322.   }
  323.   if (CurrFTRL->next) {
  324.     FAXerrno = MOREFTRSTHANFC;
  325.   }
  326.  
  327.   /*  If we got this far, all is ok! */
  328.   return(1);
  329. }
  330.  
  331. /*
  332.    SFTROkToSubmit(SFTR *SFTR);
  333.  
  334.    This function checks an Single File Transfer Record Structure for errors.
  335.    It applies the same tests as the ECSOkToSubmit function, but on a subset
  336.    of the Event Control File fields.  This subset is defined by CAS under the
  337.    function "Submit a Single File To Send" (15H).
  338.  
  339.    Reserved fields are tested for being zero; if not, they are zeroed and a
  340.    warning is set.  Likewise other fields used by the Resident Manager that
  341.    should be set to zero by the application are tested.  It they are not zero,
  342.    they are set to zero, and a warning is set.
  343.  
  344.    INPUT:  The SFTR structure for the task under consideration.
  345.  
  346.    OUTPUT: 1 or 0.
  347. */
  348.  
  349. int pascal SFTROkToSubmit(SFTR *sftr)
  350. {
  351.   DOS_ftime *time;
  352.   DOS_fdate *date;
  353.   unsigned twosec, minute, hour,
  354.            year, month, day;
  355.   struct stat fstatbuf;
  356.   int i, leap;
  357.  
  358.   /* TransferType check */
  359.   if ((sftr->TransferType < FAX_200) ||
  360.       (sftr->TransferType > FILE_TRANSFER)) {
  361.     FAXerrno = BADTRANSFERTYPE;
  362.     return(0);
  363.   }
  364.  
  365.   /* TextSize check, applies only to FAX's */
  366.   if (sftr->TransferType != FILE_TRANSFER) {
  367.     if ((sftr->TextSize < 0) ||
  368.         (sftr->TextSize > 1)) {
  369.       FAXerrno = FTRBADTEXTSIZE;
  370.       return(0);
  371.     }
  372.   }
  373.  
  374.   /* EventTime  check */
  375.   time = (DOS_ftime *)&sftr->EventTime;
  376.   twosec = time->twosecs;
  377.   minute = time->minute;
  378.   hour = time->hour;
  379.   if ((twosec < 0) || (twosec > 29) ||
  380.       (minute < 0) || (minute > 59) ||
  381.       (hour < 0) || (hour > 23)) {
  382.     FAXerrno = BADEVENTTIME;
  383.     return(0);
  384.   }
  385.  
  386.   /* EventDate  check, only if date is not NULL (NULL is OK) */
  387.   if (sftr->EventDate) {
  388.     date = (DOS_fdate *)&sftr->EventDate;
  389.     year = date->year;
  390.     month = date->month;
  391.     day = date->day;
  392.     if ((month < 1) || (month > 12) ||
  393.         (year < 0) || (year > 119)) {
  394.       FAXerrno = BADEVENTDATE;
  395.       return(0);
  396.     }
  397.     year = year + 1980;
  398.     leap = (year % 4 == 0) &&
  399.            (year % 100 != 0) ||
  400.            (year % 400 == 0);
  401.     if ((day < 1) || (day > days_in_month[leap][month])) {
  402.       FAXerrno = BADEVENTDATE;
  403.       return(0);
  404.     }
  405.   }
  406.  
  407.   /* DestinationName[]  check */
  408.   for (i=0; i<NAMELENGTH; i++) {
  409.     if (!sftr->DestinationName[i]) {
  410.       break;
  411.     }
  412.     if (!(isascii(sftr->DestinationName[i]))) {
  413.       FAXerrno = NONASCIISTRING;
  414.       return(0);
  415.     }
  416.   }
  417.   if (i == NAMELENGTH) {
  418.     FAXerrno = STRINGTOOLONG;
  419.     sftr->DestinationName[i - 1] = '\0';
  420.   }
  421.  
  422.   /* The filename must be valid... */
  423.   for (i=0; i<FULLFNAMELENGTH; i++) {
  424.     if (!(sftr->FileName[i])) {
  425.       break;
  426.     }
  427.     if (!(isascii(sftr->FileName[i]))) {
  428.       FAXerrno = FTRNONASCIISTRING;
  429.       return(0);
  430.     }
  431.   }
  432.   if (i == FULLFNAMELENGTH) {
  433.     FAXerrno = STRINGTOOLONG;
  434.     sftr->FileName[i - 1] = '\0';
  435.   }
  436.  
  437.   /* ... and present */
  438.   if (stat(sftr->FileName, &fstatbuf)) {
  439.     FAXerrno = FILETOSENDNOTFOUND;
  440.     return(0);
  441.   }
  442.  
  443.   /* Phone[]  check, first for length...  */
  444.   for (i=0; i<PHONENUMLENGTH; i++) {
  445.     if (!sftr->Phone[i]) {
  446.       break;
  447.     }
  448.   }
  449.   if (i == PHONENUMLENGTH) {
  450.     FAXerrno = STRINGTOOLONG;
  451.     sftr->Phone[i - 1] = '\0';
  452.   }
  453.   if (i == 0) {
  454.     FAXerrno = BADPHONENUMBER;
  455.     return(0);
  456.   }
  457.  
  458.   /* ...then for validity */
  459.   /* (if first character is 'm' or 'M', rest is ok) */
  460.   if (tolower(sftr->Phone[0]) != 'm') {
  461.     for (i=0; sftr->Phone[i] && (i < PHONENUMLENGTH); i++) {
  462.       if ((sftr->Phone[i] >= '0') &&
  463.           (sftr->Phone[i] <= '9')) {
  464.         break;
  465.       }
  466.     }
  467.     if (!sftr->Phone[i]) {
  468.       FAXerrno = BADPHONENUMBER;
  469.       return(0);
  470.     }
  471.   }
  472.  
  473.   /* ApplicationTag[]  check */
  474.   for (i=0; i<APPTAGLENGTH; i++) {
  475.     if (!sftr->ApplicationTag[i]) {
  476.       break;
  477.     }
  478.     if (!(isascii(sftr->ApplicationTag[i]))) {
  479.       FAXerrno = NONASCIISTRING;
  480.       return(0);
  481.     }
  482.   }
  483.   if (i == APPTAGLENGTH) {
  484.     FAXerrno = STRINGTOOLONG;
  485.     sftr->ApplicationTag[i - 1] = '\0';
  486.   }
  487.  
  488.   /* RESERVED1  check */
  489.   if (sftr->RESERVED1) {
  490.     FAXerrno = RESERVEDFIELDZEROED;
  491.     sftr->RESERVED1 = 0;
  492.   }
  493.  
  494.   /* SendCover  check */
  495.   if ((sftr->SendCover != 0) &&
  496.       (sftr->SendCover != 1)) {
  497.     FAXerrno = BADSENDCOVER;
  498.     return(0);
  499.   }
  500.  
  501.   /* RESERVED2[]  check */
  502.   for (i=0; i<23; i++) {
  503.     if (sftr->RESERVED2[i]) {
  504.       sftr->RESERVED2[i] = 0;
  505.       FAXerrno = RESERVEDFIELDZEROED;
  506.     }
  507.   }
  508.  
  509.   /* Checks of the coverpage text (pretty dangerous: we don't know how long!) */
  510.   for (i=0; (&sftr->CoverTextDummy)[i]; i++) {
  511.     if (!(isascii((&sftr->CoverTextDummy)[i]))) {
  512.       FAXerrno = NONASCIISTRING;
  513.       return(0);
  514.     }
  515.   }
  516.  
  517.   /* If reached all the way here, must be ok! */
  518.   return(1);
  519. }
  520.  
  521. /*
  522.    FTRLOkToSend(ECS *ecs, FTRLIST *ftrl);
  523.  
  524.    This function checks a File Transfer Record List Structure for errors.  It
  525.    follows the specifications for File Transfer Records documented in CAS 1.0.
  526.    It returns 1 if the FTRL is valid for a task event.
  527.  
  528.    Reserved fields are tested for being zero; if not, they are zeroed and a
  529.    warning is set.  Likewise other fields used by the Resident Manager that
  530.    should be set to zero by the application are tested.  It they are not zero,
  531.    they are set to zero, and a warning is set.
  532.  
  533.    INPUT:  The event control structure for the event sending the file, and the
  534.    File Transfer Record List Structure to be tested.
  535.  
  536.    OUTPUT: 1 or 0.
  537. */
  538.  
  539. int pascal FTRLOkToSend(ECS *ecs, FTRLIST *ftrl)
  540. {
  541.   int i;
  542.   struct stat fstatbuf;
  543.  
  544.   /* First, the file transfer: only the filename should be set */
  545.   if (ecs->EventControlFile.TransferType == FILE_TRANSFER) {
  546.  
  547.     /* All the bytes before the filename should be zero ... */
  548.     for (i=0; i<15; i++) {
  549.       if ((&ftrl->OneFTR.FileType)[i]) {
  550.         FAXerrno = FTRFIELDZEROED;
  551.         (&ftrl->OneFTR.FileType)[i] = 0;
  552.       }
  553.     }
  554.  
  555.     /* ... and all the bytes after the filename should be also zero */
  556.     for (i=95; i<97; i++) {
  557.       if ((&ftrl->OneFTR.FileType)[i]) {
  558.         FAXerrno = FTRFIELDZEROED;
  559.         (&ftrl->OneFTR.FileType)[i] = 0;
  560.       }
  561.     }
  562.   }
  563.  
  564.   /* Now, if TransferType is one of the fax types */
  565.   else {
  566.  
  567.     /* FileType check */
  568.     if ((ftrl->OneFTR.FileType < 0) ||
  569.         (ftrl->OneFTR.FileType > 2)) {
  570.       FAXerrno = FTRBADFILETYPE;
  571.       return(0);
  572.     }
  573.  
  574.     /* TextSize check */
  575.     if ((ftrl->OneFTR.TextSize < 0) ||
  576.         (ftrl->OneFTR.TextSize > 1)) {
  577.       FAXerrno = FTRBADTEXTSIZE;
  578.       return(0);
  579.     }
  580.  
  581.     /* Fields FileStatus through PageCount should be 0 */
  582.     for (i=2; i<15; i++) {
  583.       if ((&ftrl->OneFTR.FileType)[i]) {
  584.         FAXerrno = FTRFIELDZEROED;
  585.         (&ftrl->OneFTR.FileType)[i] = 0;
  586.       }
  587.     }
  588.  
  589.     /* AddPageIncrements check: warning only, out-of-range values are ignored */
  590. /*  if ((ftrl->OneFTR.AddPageIncrements < 0) ||
  591.         (ftrl->OneFTR.AddPageIncrements > 7)) {
  592.       FAXerrno = FTRBADPAGEINCREMENTS;
  593.     }     (Actually, values from 0 to 127 are accepted and used.) */
  594.  
  595.     /* PageLength check */
  596.     if ((ftrl->OneFTR.PageLength < -1) ||
  597.         (ftrl->OneFTR.PageLength > 127)) {
  598.       FAXerrno = FTRBADPAGELENGTH;
  599.       return(0);
  600.     }
  601.   }
  602.  
  603.   /* In any case, the filename must be valid... */
  604.   for (i=0; i<FULLFNAMELENGTH; i++) {
  605.     if (!(ftrl->OneFTR.FileName[i])) {
  606.       break;
  607.     }
  608.     if (!(isascii(ftrl->OneFTR.FileName[i]))) {
  609.       FAXerrno = FTRNONASCIISTRING;
  610.       return(0);
  611.     }
  612.   }
  613.   if (i == FULLFNAMELENGTH) {
  614.     FAXerrno = STRINGTOOLONG;
  615.     ftrl->OneFTR.FileName[i - 1] = '\0';
  616.   }
  617.  
  618.   /* ... and present */
  619.   if (stat(ftrl->OneFTR.FileName, &fstatbuf)) {
  620.     FAXerrno = FILETOSENDNOTFOUND;
  621.     return(0);
  622.   }
  623.  
  624.   /* ...and the last field is completely reserved */
  625.   for (i=0; i<FTRRESERVED; i++) {
  626.     if (ftrl->OneFTR.RESERVED[i]) {
  627.       FAXerrno = FTRRESERVEDZEROED;
  628.       ftrl->OneFTR.RESERVED[i] = 0;
  629.     }
  630.   }
  631.  
  632.   /* If we passed all that, must be ok! */
  633.   return(1);
  634. }
  635.  
  636. void pascal free_FTRLIST(FTRLIST *ftrl)
  637. {
  638.   FTRLIST *CurrFTRL, *LastFTRL;
  639.   int i;
  640.  
  641.   LastFTRL = ftrl;
  642.   for (i=1; LastFTRL->next; i++) {  /* find last */
  643.     LastFTRL = LastFTRL->next;
  644.   }
  645.  
  646.   /* Free them, from last backwards, until only the first is left */
  647.   while(LastFTRL != ftrl) {
  648.     CurrFTRL = ftrl;                      /* reset to beginning of list */
  649.     while (CurrFTRL->next != LastFTRL) {  /* and go to next-to-last */
  650.       CurrFTRL = CurrFTRL->next;
  651.     }
  652.     free(LastFTRL);                /* free the last one, */
  653.     LastFTRL = CurrFTRL;           /* and name the next-to-last the last */
  654.   }                    /* loop ends when last is the first */
  655.   free(LastFTRL);      /* so free it, and we're done.  */
  656. }
  657.  
  658. void pascal freeup(ECS *ecs)
  659. {
  660.   FTRLIST *CurrFTRL, *LastFTRL;
  661.   size_t CoverLength = ecs->EventControlFile.FTROffset - 383;
  662.   int i,
  663.       FileCount = ecs->EventControlFile.FileCount;
  664.  
  665.   /* If cover, free it */
  666.   if (CoverLength) {
  667.     free(ecs->CoverPageText);
  668.   }
  669.  
  670.   /* If there is an FTRLIST,  free FTRL's, up to FileCount or last FTRL */
  671.   if (ecs->FirstFTR) {
  672.     LastFTRL = ecs->FirstFTR;
  673.     for (i=1; ((LastFTRL->next) && (i < FileCount)) ; i++) {  /* find last */
  674.       LastFTRL = LastFTRL->next;
  675.     }
  676.  
  677.     /* Free them, from last backwards, until only the first is left */
  678.     while(LastFTRL != ecs->FirstFTR) {
  679.       CurrFTRL = ecs->FirstFTR;             /* reset to beginning of list */
  680.       while (CurrFTRL->next != LastFTRL) {  /* and go to next-to-last */
  681.         CurrFTRL = CurrFTRL->next;
  682.       }
  683.       free(LastFTRL);                /* free the last one, */
  684.       LastFTRL = CurrFTRL;           /* and name the next-to-last the last */
  685.     }                    /* loop ends when last is the first */
  686.     free(LastFTRL);      /* so free it, and we're done.  */
  687.   }
  688.  
  689.   /* Finally, the event structure itself */
  690.   free(ecs);
  691. }
  692.  
  693. int pascal ValidTime(CAS_TIME *time)
  694. {
  695.   if ((time->Hour < 0) || (time->Hour > 23)) {
  696.     return(0);
  697.   }
  698.   if ((time->Minute < 0) || (time->Minute > 59)) {
  699.     return(0);
  700.   }
  701.   if ((time->Second < 0) || (time->Second > 59)) {
  702.     return(0);
  703.   }
  704.   return(1);
  705. }
  706.  
  707. int pascal ValidDate(CAS_DATE *date)
  708. {
  709.   int leap;
  710.  
  711.   if ((date->Month < 1) || (date->Month > 12) ||
  712.       (date->Year < 1980) || (date->Year > 2099)) {
  713.     return(0);
  714.   }
  715.   leap = (date->Year % 4 == 0) &&
  716.          (date->Year % 100 != 0) ||
  717.          (date->Year % 400 == 0);
  718.   if ((date->Day < 1) ||
  719.       (date->Day > days_in_month[leap][date->Month])) {
  720.     return(0);
  721.   }
  722.   return(1);
  723. }
  724.